import { glUtils } from "../GLUtils";
import { UIMgr } from "../UIMgr";
import BaseComponentByHall from "./BaseComponentByHall";



const { ccclass, property } = cc._decorator;


/**
 * 主界面 继承此类
 * 
 * !! 注意 !!
 * 在主界面下必须有两节点 
 * pn_Shadow 带组件(BlockInputEvents)
 * pn_Root
 * 
 * 
 */

@ccclass
export default class BaseUIMgr extends BaseComponentByHall {

    /** 根节点 */
    @property(cc.Node)
    pn_Root: cc.Node = null;
    /** 蒙版  阻挡点击 */
    @property(cc.Node)
    pn_Shadow: cc.Node = null;
    /** 弹框数据表 */
    _PageDataMap: {
        [key: string]: {
            path: string,
            haveShadow: boolean,
            node: cc.Node,
        }
    } = {};
    /** 需要蒙版的弹框数量 */
    _ShadowCount = 0;
    /** 创建新的弹框时不隐藏前一个弹框 */
    _donotHideOld: boolean = false;


    /** 蒙版显示回调 */
    _shadowFadeInCallback
    /** 蒙版隐藏回调 */
    _shadowFadeOutCallback

    /**使用常驻节点作为根节点 公共节点
     *  
     */
    useSolidifyRoot() {
        this.pn_Root = UIMgr.solidifyRoot;
        //不隐藏前一个弹框,因为不确定公用节点是否插入到了顺序中  (future优化)
        this._donotHideOld = true;
    }

    /** 初始化
     * 
     * @param parent 
     */
    initEvent() {

        this.pn_Shadow && (this.pn_Shadow.active = false)
        this.onBaseEvent("open")
        this.onBaseEvent("close")
        this.onBaseEvent("closeLast")
    }

    //继承组件,但不作为组件
    /** 释放
     * 
     */
    releaseEvent() {
        this.offBaseEvent("open")
        this.offBaseEvent("close")
        this.offBaseEvent("closeLast")
    }

    /** 打开一个弹框
     * 
     * @param path 
     * @param haveShadow //默认打开(已废弃)
     * @param callback 
     * @param donotHideOld 不隐藏上一个弹框|界面
     * 
     * !!!注意!!! 
     * 使用open打开的节点,主动关闭必须通过close,不可自己destroy
     * 即发出"close"事件,或者调用close()
     * 
     * 
     * 
        本项目不建议使用
        BaseCustomEvent.emit("open", {
            path: "",
            haveShadow: true,
        })
     */
    open(data: {
        path: string
        haveShadow?: any
        callback?: (sc: any) => void
        donotHideOld?: boolean
    }) {
        cc.log("open node:", data.path)
        data.haveShadow = true
        this._addShadowCount(data.haveShadow)
        this.loadAndCreatePrefab(data.path, this.pn_Root, (sc: any, isCancel: boolean) => {

            this._setOld(this._donotHideOld || (data.donotHideOld || false));
            let node = this.pn_Root.children[this.pn_Root.childrenCount - 1]
            let key = node.uuid
            this._PageDataMap[key] = {
                path: data.path,
                haveShadow: data.haveShadow,
                node: node,
            }
            if (data.callback) {
                data.callback(sc);
            }
        })
    }

    /** 同时取数据 并加载预制体
     * 
     * @param data 
     * @param path 预制体路径
     * @param haveShadow (已废弃)
     * @param donotHideOld 不隐藏上一个弹框|界面
     * @param msgData 取数据需要的数据
     * @param getDataCb 取数据方法 async Function
     */
    async open_async(data: {
        path: string
        haveShadow?: any
        donotHideOld?: boolean
        msgData?: any
        getDataCb: (msgData: any) => void
    }) {
        cc.log("open node:", data.path)
        data.haveShadow = true
        this._addShadowCount(data.haveShadow)
        let c: [any, any] = await this.getDataAndLoadPrefabCreate(data.getDataCb, data.path, data.msgData, this.pn_Root)
        this._setOld(this._donotHideOld || (data.donotHideOld || false));
        let node = this.pn_Root.children[this.pn_Root.childrenCount - 1]
        let key = node.uuid
        this._PageDataMap[key] = {
            path: data.path,
            haveShadow: data.haveShadow,
            node: node,
        }

        return new Promise<[any, any]>((reslove) => {
            reslove(c)
        })
    }

    /** 关闭一个弹框
     * 
     * @param uuid 
     * 
        BaseCustomEvent.emit("close", this.node.uuid)
     */
    close(uuid: string) {
        cc.log("close node:", uuid)
        let D = this._PageDataMap[uuid]
        if (D) {
            let node = D.node
            //关闭前打开前一个弹框
            this._setOld(true);
            this._reduceShadowCount(D.haveShadow)
            cc.log("close node:", node.name)
            delete this._PageDataMap[uuid]
            if (node && cc.isValid(node)) {
                node.destroy();
            }
            return
        }
        cc.warn(this.node.name, "尝试关闭一个不存在的弹框", uuid, this._PageDataMap)
        // glUtils.testErrorLog()



    }

    /** 关闭最上面一个弹框
     * 
     */
    closeLast() {
        let node = this.pn_Root.children[this.pn_Root.childrenCount - 1]
        if (node) {
            this.close(node.uuid)
        } else {
            cc.warn("没有可以关闭的弹框了", this.pn_Root.children)
        }
    }

    /** 关闭所有弹框
     * 
     */
    closeAll() {
        let keys = Object.keys(this._PageDataMap)
        let len = keys.length;
        for (let i = 0; i < len; i++) {
            let key = keys[i];
            this.close(key)
        }
        this._PageDataMap = {};
        this._ShadowCount = 0;
        this.__setShadow(false)
    }
    /** 设置前一个弹框是否显示
     * 
     * @param flag 
     */
    _setOld(flag: boolean) {
        let node = this.pn_Root.children[this.pn_Root.childrenCount - 2]
        if (node) {
            node.active = flag;
        }
    }






    //蒙版控制 
    /** 增加蒙版值
     * 
     * @param haveShadow 
     */
    _addShadowCount(haveShadow: any) {
        if (haveShadow) {
            this._ShadowCount++;
        }
        this.__setShadow(this._ShadowCount > 0)
        this._ShadowCount == 1 && this._shadowFadeInCallback && this._shadowFadeInCallback(this.pn_Shadow)
    }
    /** 减少
     * 
     * @param haveShadow 
     */
    _reduceShadowCount(haveShadow: boolean) {
        if (haveShadow) {
            this._ShadowCount--;
        }
        this.__setShadow(this._ShadowCount > 0)
        this._ShadowCount == 0 && this._shadowFadeOutCallback && this._shadowFadeOutCallback(this.pn_Shadow)
    }
    __setShadow(flag: boolean) {

        this.pn_Shadow && (
            this.pn_Shadow.active = flag
        );

    }

    setShadowFadeInCallback(cb) {
        this._shadowFadeInCallback = cb;
    }
    setShadowFadeOutCallBack(cb) {
        this._shadowFadeOutCallback = cb;

    }

}
